В интернете полно просто информации по оператору millis для Arduino. Первоначально, когда я обращался к этому материалу для изучения millis, то почему-то мне трудно было соотнести, что и как там делается. Подсознательно я понимал, что должно происходить, но описание меня не удовлетворяло! Оно не позволяло все "разложить по полочкам" в моем сознании и наслаждаться неким перфекционизмом в моей черепной коробке. В итоге, после полного осознания как и что происходит, я решил накатать свою версию происходящего, с исчерпывающим описанием указывающим на точный характер фактов и вещей происходящего…

 Итак, прежде всего о том, как же бывает в жизни и чем по сути delay отличается от millis. Сто раз уже каждый из нас читал, что одна функция позволяет не нагружать микроконтроллер, то есть выполнять какие-то другие задачи, а вторая (delay) ждет, пока выполнится программа ожидания, а лишь потом продолжает работать по написанному алгоритму.

 Здесь есть доля вранья, так как даже millis немного притормаживает процесс, но несоизмеримо по сравнению с delay. В целом это можно представить так! Скажем, вы поставили в духовку курицу и знаете, что через полчаса она будет готова. Так вот, если это delay, то считайте вы взяли табуретку и сели напротив духовки, чтобы смотреть на часы над духовкой и на то, как жарится курица, пока она окончательно не приготовиться. Теперь, вы не можете пойти и посмотреть телевизор, если он у вас в другой комнате.
 А что же такое millis? Это все равно, что вы дали себе установку, что курица у вас там жарится, но пойду делать что-то другое, при этом время от времени присматривая за часами. И вот раз в 5 минут вы заходите и смотрите на таймер на духовке, при этом параллельно выполняя что-то другое. Вот также и программа, она имеет свой замкнутый цикл (void loop()), в котором прописана команда на сравнение прошедшего времени с тем, что мы отметили для "готовки курицы".  То есть какое-то, ну совсем незначительное время, вы все же тратите на проверку времени, как и проверка для millis в этом цикле команды, но это пустяк по сравнению с delay. Что в итоге позволят тратить большую часть времени все же на условно полезные вещи.

Из-за этой особенности при использовании millis, надо сказать о неизбежном. Само по себе millis - это уже какое-то прошедшее время с начала включения нашего микроконтроллера. Оно так и расшифровывается как миллисекунды, а бывает micros (микросекунды). При этом дополнительно всегда вводится переменная времени, которая как раз и будет сравнивать прошедшее время с начала запуска микроконтроллера, со временем до конца «приготовления курицы». Как только критерии сравнения одного времени с другим станут актуальными для нас, мы сможем выполнить нужное действие «достать курицу из духовки». Вот эти мысли мне хотелось бы довести до вас и может когда-нибудь вернуться к ним снова, чтобы прочитать и поразмыслить над жизненностью ситуаций, который проходят все с той же аналогией не важно, будь то кухня или алгоритм работы программы в микроконтроллере.

Теперь же обязательно скетч с пояснениями работы.

unsigned long timing; // Переменная для хранения времени, первоначально это 0 секунд, 0 часов, 0 суток и так далее...
void setup() { 
Serial.begin(9600);
pinMode(13, OUTPUT);
} // прописываем выход для 13 ножки
void loop() {

 if (millis() - timing > 10000){ // получается что millis "растет", а timing взято с последнего удовлетворения условию, в итоге как только millis пройдет более того, что указано в неравенстве, в нашем случае станте больше millis на 10000, то светодид загорится
   digitalWrite(13, HIGH);
 }

  if (millis() - timing > 20000){ // millis "растет" дальше, во временном интервале между 10000 и 20000 светодиод будет гореть, а потом при условии разницы более 20000 он погаснет и millis приравняется timing, то есть начнется все заново
  timing = millis(); digitalWrite(13, LOW);
 }    
}

Скетч с примером мигания светодиодом millis

Возможные проблемы

В старых Ардуинках, по крайней мере с корпусом DIP, у меня наблюдалось следующее, - этот скетч не работал. Светодиод просто будто разгорался и постоянно горел. Возможно это было связано с контроллером 16u2 на самой плате. Ведь через него заливается скетч в микроконтроллер 328. А вот в новой стоял CH340 и таких проблем не было! ** - Позже выяснилось, что надо было прописать 13 ножку как выход в void setup(). В этом случае стало работать для всех версий Ардуино.

Еще один интересный момент это переполнение millis. Ведь что такое millis, это отсчет времени от начала работы процессора, нашей Ардуинки. В итоге это время же куда-то пишется... А раз так, то данные там все растут и растут. В конце концов регистр под это время заканчивается и millis просто виснет.

Переполнение millis в Arduino происходит, когда переменная millis, которая хранит количество миллисекунд, прошедших с момента запуска программы, достигает максимального значения (примерно 50 дней). После этого происходит переполнение переменной и она начинает считать время с нуля. Это может привести к неправильной работе программы, если она основана на точном измерении времени. Для решения этой проблемы можно использовать специальные функции и библиотеки, которые учитывают переполнение millis.

Комментарии  

+2 #1 Вячеслав 21.09.2020 11:56
Ты мой герой !!! Спасибо тебе !!!!